package com.ruoyi.durian.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.constant.DurianConstant;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.enums.DurianRedisKeysType;
import com.ruoyi.common.enums.OrderType;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.RedisGeoUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.rabbitmq.RabbitSendUtils;
import com.ruoyi.durian.domain.*;
import com.ruoyi.durian.domain.dto.OrderEvaluateDto;
import com.ruoyi.durian.domain.dto.SaveOrderDto;
import com.ruoyi.durian.domain.vo.SendMessageReesultVo;
import com.ruoyi.durian.mapper.*;
import com.ruoyi.durian.service.LlMapService;
import com.ruoyi.durian.service.LlOrderService;
import com.ruoyi.system.service.ISysUserService;
import org.redisson.RedissonMultiLock;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * @author lenovo
 * @description 针对表【ll_order(订单模块-订单表)】的数据库操作Service实现
 * @createDate 2024-07-29 21:04:10
 */
@Service
public class LlOrderServiceImpl extends ServiceImpl<LlOrderMapper, LlOrder>
        implements LlOrderService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedisGeoUtils redisGeoUtils;

    @Resource
    private LlOrderMapper llOrderMapper;

    @Resource
    private LlOrderInfoMapper llOrderInfoMapper;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private RabbitSendUtils rabbitSendUtils;

    @Resource
    private LlCardPackageMapper llCardPackageMapper;

    @Resource
    private LlCouponMapper llcouponMapper;

    @Resource
    private TPayMapper tPayMapper;

    @Resource
    private LlMapService llMapService;

    @Resource
    private LlUserFriendMapper llUserFriendMapper;

    @Resource
    private ISysUserService userService;

    /**
     * 乘客取消订单
     *
     * @param orderId 订单id
     * @return
     */
    @Override
    @Transactional
    public AjaxResult closeOrder(Integer orderId) {

        Integer userId = SecurityUtils.getUserId().intValue();

        RLock redLock = redissonClient.getLock(DurianConstant.START_ORDER_KEY);
        RedissonMultiLock lock = new RedissonMultiLock(redLock);
        lock.lock();
        try {
            // 获取订单在订单地图中的key
            String orderString = stringRedisTemplate.opsForValue().get(DurianRedisKeysType.ORDER.getKey() + userId);
            LlOrder order = JSONObject.parseObject(orderString, LlOrder.class);
            if (order.getStatus() >= OrderType.WAITING_AFTER.getCode()) {
                return AjaxResult.error("司机已到达指定地点无法取消订单");
            }
            // 删除redis中的订单
            stringRedisTemplate.delete(DurianRedisKeysType.ORDER.getKey() + userId);
            // 删除订单在地图中的位置
            redisGeoUtils.geoDel(DurianRedisKeysType.PERSON.getKey() + userId, orderString);

            LlOrder llOrder = llOrderMapper.selectById(orderId);
            LambdaQueryWrapper<LlOrderInfo> qw = new LambdaQueryWrapper<>();
            qw.eq(LlOrderInfo::getOrderId, orderId);
            LlOrderInfo orderInfo = llOrderInfoMapper.selectOne(qw);

            llOrder.setStatus(OrderType.DELETE_ORDER.getCode());
            orderInfo.setStatus(OrderType.DELETE_ORDER.getCode());

            llOrderMapper.updateById(llOrder);
            llOrderInfoMapper.updateById(orderInfo);

            SendMessageReesultVo resultVo = new SendMessageReesultVo();
            resultVo.setType(1);
            resultVo.setReceiveId(orderInfo.getDriverId());
            resultVo.setMessage("乘客取消订单。。。。");
            resultVo.setOrderId(orderId);
            rabbitSendUtils.sendMessage(resultVo.getReceiveId(), JSONObject.toJSONString(resultVo));

            resultVo.setReceiveId(userId.intValue());
            resultVo.setMessage("取消订单成功！！！！");
            rabbitSendUtils.sendMessage(resultVo.getReceiveId(), JSONObject.toJSONString(resultVo));
        } finally {
            lock.unlock();
        }

        return AjaxResult.success("取消成功");
    }

    /**
     * 结算使用优惠券
     *
     * @param orderId
     * @param couponId
     * @return
     */
    @Override
    public AjaxResult useCoupon(Integer orderId, Integer couponId) {
        Integer userId = 2030;

        if (couponId == null || orderId == null) {
            return AjaxResult.error("订单不存在，或者优惠券已使用");
        }

        //按照订单id查询订单
        LlOrder llOrder = llOrderMapper.selectById(orderId);
        //获取原本的订单价格
        BigDecimal price = llOrder.getPrice();
        //按照卡包的优惠券id查询卡包
        LlCardPackage cardPackage = llCardPackageMapper.selectById(couponId);
        if (llOrder == null || cardPackage == null) {
            return AjaxResult.error("订单不存在，或者优惠券已使用");
        }
        //根据卡包里面对应的优惠券id进入优惠券表查询优惠券具体的信息
        LlCoupon llCoupon = llcouponMapper.selectById(cardPackage.getCouponId());

        //优惠券状态   1 打折  2 满减
        if (llCoupon.getType() == 1) {
            //获取折扣
            BigDecimal discount = BigDecimal.valueOf(llCoupon.getSale());
            //计算折扣后的价格
            BigDecimal discountPrice = price.multiply(discount.divide(BigDecimal.valueOf(10)));
            //优惠的金额
            BigDecimal subtract = price.subtract(discountPrice);
            if (subtract.compareTo(llCoupon.getSaleMoney()) >= 0) {
                llOrder.setPrice(llCoupon.getSaleMoney());
            }
            //将订单价格修改为折扣后的价格
            llOrder.setPrice(discountPrice);
        } else {

            //获取满减
            BigDecimal discount = BigDecimal.valueOf(llCoupon.getSale());
            if (price.compareTo(llCoupon.getMax()) >= 0) {
                //计算满减后的价格
                BigDecimal discountPrice = price.subtract(discount);
                //将订单价格修改为满减后的价格
                llOrder.setPrice(discountPrice);
            } else {
                return AjaxResult.error("不满足满减条件");
            }
        }

        return AjaxResult.success("优惠券使用成功");
    }

    /**
     * 首页订单数据
     *
     * @return
     */
    @Override
    public AjaxResult orderNumInfo() {
        // 今日交易额度
        BigDecimal priceAll = tPayMapper.selectPriceAll();
        // 今日订单数量
        Integer orderNum = llOrderMapper.selectOrderNum();
        // 今日访问人数
        Integer logInNum = llOrderMapper.selectLogInNum();
        // 今日新增人数
        Integer newNum = llOrderMapper.selectNewNum();
        // 累计用户量
        Integer personNum = llOrderMapper.selectPersonNum();
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("priceAll", priceAll);
        map.put("orderNum", orderNum);
        map.put("logInNum", logInNum);
        map.put("newNum", newNum);
        map.put("personNum", personNum);
        return AjaxResult.success(map);
    }

    /**
     * 首页展示的订单
     *
     * @return
     */
    @Override
    public List<LlOrder> selectLsit() {
        LambdaQueryWrapper<LlOrder> qw = new LambdaQueryWrapper<>();
        qw.orderByDesc(LlOrder::getCreateTime);
        return llOrderMapper.selectList(qw);
    }

    /**
     * 折线图-一周内交易额
     *
     * @return
     */
    @Override
    public AjaxResult priceOnWeek() {
        List<Map<Object, String>> list = llOrderMapper.selectPriceOnWeek();
        return AjaxResult.success(list);
    }

    /**
     * 饼状图-车型接单占比
     *
     * @return
     */
    @Override
    public AjaxResult carTypeOnOrder() {
        List<Map<Object, String>> list = llOrderMapper.carTypeOnOrder();
        return AjaxResult.success(list);
    }

    /**
     * 柱状图-订单状态
     *
     * @return
     */
    @Override
    public AjaxResult orderTypeList() {
        List<Map<Object, String>> list = llOrderMapper.orderTypeList();
        return AjaxResult.success(list);
    }

    /**
     * 正在进行中的订单数量查询
     *
     * @return
     */
    @Override
    public Long findOrderIng() {
        Long userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<LlOrder> wrapper = new LambdaQueryWrapper<LlOrder>();
        wrapper.eq(LlOrder::getUserId, userId)
                .between(LlOrder::getStatus, OrderType.READY.getCode(), OrderType.END.getCode());
        return llOrderMapper.selectCount(wrapper);

    }

    /**
     * 获取当前用户的总里程数
     *
     * @return
     */
    @Override
    public AjaxResult getAllMileage() {
        Long userId = SecurityUtils.getUserId();
        QueryWrapper<LlOrder> wrapper = new QueryWrapper<>();
        QueryWrapper<LlOrder> queryWrapper = wrapper.select("sum(mileage) as mileage")
                .eq("user_id", userId.intValue());
        LlOrder llOrder = llOrderMapper.selectOne(queryWrapper);

        return AjaxResult.success(null == llOrder || null == llOrder.getMileage()
                ? 0 : llOrder.getMileage());
    }

    @Override
    @Transactional
    public AjaxResult delByOrderId(Integer id) {
        removeById(id);
        LambdaQueryWrapper<LlOrderInfo> eq = new LambdaQueryWrapper<LlOrderInfo>().eq(LlOrderInfo::getOrderId, id);
        llOrderInfoMapper.delete(eq);
        return AjaxResult.success("删除成功");
    }

    /**
     * 订单总数
     *
     * @return
     */
    @Override
    public Long getOrderCount() {
        Long userId = SecurityUtils.getUserId();
        return llOrderMapper.getOrderCount(userId);
    }

    /**
     * 乘客对评价中司机的评价
     *
     * @param orderEvaluateDto
     * @return
     */
    @Override
    public AjaxResult evaluate(OrderEvaluateDto orderEvaluateDto) {
        Integer driverId = 2205;

        RLock rLock = redissonClient.getLock(DurianConstant.START_ORDER_KEY);
        RedissonMultiLock lock = new RedissonMultiLock(rLock);
        lock.lock();
        try {
            String order = stringRedisTemplate.opsForValue().get(DurianRedisKeysType.ORDER.getKey() + orderEvaluateDto.getUserId());
            LlOrder llOrder = JSON.parseObject(order, LlOrder.class);
            if (llOrder == null) {
                return AjaxResult.error("订单错误");
            }
            LlOrder llOrderTwo = llOrderMapper.selectById(orderEvaluateDto.getOrderId());
            if (llOrderTwo == null || llOrderTwo.getStatus() != OrderType.PAYMENT_COMPLETED.getCode()) {
                return AjaxResult.error("订单正在进行中,无法进行评价");
            }
            LambdaUpdateWrapper<LlOrderInfo> qw = new LambdaUpdateWrapper<>();
            qw.eq(LlOrderInfo::getOrderId, llOrderTwo.getId());
            LlOrderInfo llOrderInfo = llOrderInfoMapper.selectOne(qw);
            if (llOrderInfo.getStatus() != OrderType.PAYMENT_COMPLETED.getCode()) {
                return AjaxResult.error("订单未完成");
            }
            llOrderInfo.setAllRight(orderEvaluateDto.getAllRight());
            llOrderInfo.setService(orderEvaluateDto.getService());
            llOrderInfoMapper.updateById(llOrderInfo);

            stringRedisTemplate.opsForValue().set(DurianRedisKeysType.ORDER.getKey() + orderEvaluateDto.getUserId(), JSONObject.toJSONString(llOrderTwo));
            rabbitSendUtils.sendMessage(llOrder.getUserId(), "已完成对司机的评价!!!");
            rabbitSendUtils.sendMessage(driverId, "乘客已经对您进行评价");
        } finally {
            lock.unlock();
        }
        return AjaxResult.success("评价成功");
    }

    /**
     * 定时任务检查未支付的订单
     */
    @Override
    public Integer checkNotPayOrder() {
        LambdaQueryWrapper<LlOrder> qw = new LambdaQueryWrapper<>();
        qw.eq(LlOrder::getStatus, OrderType.TO_PAY.getCode());
        List<LlOrder> llOrders = llOrderMapper.selectList(qw);
        if (!CollectionUtils.isEmpty(llOrders)) {
            llOrders.forEach(item -> {
                rabbitSendUtils.sendMessage(item.getUserId(), "订单未支付,请及时支付");
            });
        }
        return llOrders.size();
    }

    /**
     * 乘客发起订单
     *
     * @return
     */
    @Override
    public AjaxResult saveOrder(SaveOrderDto saveOrderDto) {

        Integer userId = 2030;

        RLock redLock = redissonClient.getLock(DurianConstant.START_ORDER_KEY);
        RedissonMultiLock lock = new RedissonMultiLock(redLock);
        lock.lock();
        try {
            String orderString = stringRedisTemplate.opsForValue().get(DurianRedisKeysType.ORDER.getKey() + userId);
            LlOrder llOrderRedis = JSONObject.parseObject(orderString, LlOrder.class);

            // 如果乘客订单状态为0表示当前没有订单，否则代表乘客因为网络波动重连
            if (null != llOrderRedis) {
                return AjaxResult.success("订单正在进行中！！！！");
            }

            LlOrder order = new LlOrder();
            LlMap start = llMapService.getById(saveOrderDto.getStartAddressId());
            LlMap end = llMapService.getById(saveOrderDto.getEndAddressId());
            // 封装订单
            order.setBeginName(start.getName());
            order.setBeginId(start.getId());
            order.setFinishName(end.getName());
            order.setFinishId(end.getId());
            order.setStatus(OrderType.WAITING_BEFORE.getCode());
            order.setUserId(userId);
            order.setIsDelete(0);

            // 如果是预约叫车
            if (saveOrderDto.getOrderType() == 2) {
                order.setStartTime(DateUtils.dateTime(DateUtils.YYYY_MM_DD_HH_MM_SS, saveOrderDto.getStartTime()));
            }
            // 封装订单详情
            LlOrderInfo orderInfo = new LlOrderInfo();
            // 帮别人叫车
            if (saveOrderDto.getOrderType() == 3) {
                orderInfo.setFriendId(saveOrderDto.getFriendId());
                orderInfo.setIsMe(1);
                LlUserFriend friend = llUserFriendMapper.selectById(saveOrderDto.getFriendId());
                order.setUserPhone(friend.getFriendPhone().toString());
            } else {
                SysUser sysUser = userService.selectUserById(Long.valueOf(userId));
                order.setUserPhone(sysUser.getPhonenumber());
            }
            llOrderMapper.insert(order);

            orderString = JSONObject.toJSONString(order);
            stringRedisTemplate.opsForValue().set(DurianRedisKeysType.ORDER.getKey() + userId, orderString);

            orderInfo.setOrderId(order.getId());
            orderInfo.setUserId(userId);
            orderInfo.setIsMe(0);

            orderInfo.setStatus(OrderType.WAITING_BEFORE.getCode());
            orderInfo.setInvoiceStatus(1);
            orderInfo.setIsDelete(0);

            llOrderInfoMapper.insert(orderInfo);
        } finally {
            lock.unlock();
        }
        return AjaxResult.success("订单创建成功");
    }
}




